package sc.prototype.pfs.eventnotify;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import sc.prototype.common.Profiler;
import sc.prototype.pfs.eventnotify.collector.NoticeFactory;
import sc.prototype.pfs.eventnotify.excep.CollectContentException;
import sc.prototype.pfs.eventnotify.excep.NotifyException;
import sc.prototype.pfs.eventnotify.executor.NotifyTaskManager;
import sc.prototype.pfs.eventnotify.filter.NotifyConfigFilter;
import sc.prototype.pfs.eventnotify.model.Notice;
import sc.prototype.pfs.eventnotify.model.NoticeContent;
import sc.prototype.pfs.eventnotify.model.NotifyConfig;
import sc.prototype.pfs.eventnotify.model.NotifyContext;
import sc.prototype.pfs.eventnotify.model.NotifyEvent;
import sc.prototype.pfs.eventnotify.repo.NoticeManager;
import sc.prototype.pfs.eventnotify.repo.NotifyConfigCache;

public class DefaultNotifyToolkit implements NotifyToolkit {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    NotifyConfigCache notifyConfigCache;

    NotifyConfigFilter notifyConfigFilter;

    NoticeFactory noticeFactory;

    NoticeManager noticeManager;

    NotifyTaskManager notifyTaskManager;

    public void validateEvent(NotifyEvent event) {
        Assert.notNull(event, "事件不能为空！");
        Assert.notNull(event.getEventType(), "事件类型不能为空！");
        Assert.notNull(event.getEventKey(), "事件键值不能为空！");
    }

    @Override
    public void notifyEvent(NotifyEvent event) throws NotifyException {
        validateEvent(event);
        NotifyContext context = new NotifyContext();
        context.setEvent(event);
        String logPrefix = "事件通知-" + DateTime.now().toString("HHmmssSSS-") + event.getEventKey();
        context.setLogPrefix(logPrefix);
        Profiler.start("开始处理");
        try {
            Profiler.enter("获取通知配置缓存");
            List<NotifyConfig> configs = notifyConfigCache.getAll();
            Profiler.release();

            Profiler.enter("筛选通知配置");
            configs = notifyConfigFilter.filter(event, configs);
            if (CollectionUtils.isEmpty(configs)) {
                logger.info("{}：没有匹配的通知配置", logPrefix);
                Profiler.release();
                return;
            }
            context.setConfigs(configs);
            Profiler.release();

            Profiler.enter("生成通知");
            List<Notice> notices = new ArrayList<Notice>();
            List<NoticeContent> noticeContents = new ArrayList<NoticeContent>();
            createNotices(context, notices, noticeContents);
            Assert.notEmpty(notices, "生成通知为空，配置错误！");
            Profiler.release();

            Profiler.enter("保存通知");
            saveNotices(context, notices, noticeContents);
            Profiler.release();

            Profiler.enter("发送通知");
            sendNotices(context, notices);
            Profiler.release();
        } catch (Exception e) {
            Profiler.enter("事件通知处理异常：" + e.getMessage());
            Profiler.release();
            logger.error(logPrefix + "：事件通知处理异常：" + context, e);
            throw new NotifyException(logPrefix + "：事件通知处理异常：", e);
        } finally {
            Profiler.release();
            logger.info("{}，{}", logPrefix, Profiler.dump());
            Profiler.reset();
        }
    }

    public void createNotices(NotifyContext context, List<Notice> notices, List<NoticeContent> noticeContents)
            throws CollectContentException {
        for (NotifyConfig config : context.getConfigs()) {
            NoticeFactory.CreateStuff createStuff = noticeFactory.create(config, context);
            if (createStuff.hasNotice()) {
                notices.addAll(createStuff.getNotices());
                noticeContents.addAll(createStuff.getNoticeContents());
            }
        }
    }

    public void saveNotices(NotifyContext context, List<Notice> notices, List<NoticeContent> noticeContents) {
        noticeManager.insertNoticeStuff(notices, noticeContents);
    }

    public void sendNotices(NotifyContext context, List<Notice> notices) {
        for (Notice notice : notices) {
            notifyTaskManager.processNotifyTask(notice, context);
        }
    }

    public void setNotifyConfigCache(NotifyConfigCache notifyConfigCache) {
        this.notifyConfigCache = notifyConfigCache;
    }

    public void setNotifyConfigFilter(NotifyConfigFilter notifyConfigFilter) {
        this.notifyConfigFilter = notifyConfigFilter;
    }

    public void setNoticeFactory(NoticeFactory noticeFactory) {
        this.noticeFactory = noticeFactory;
    }

    public void setNoticeManager(NoticeManager noticeManager) {
        this.noticeManager = noticeManager;
    }

    public void setNotifyTaskManager(NotifyTaskManager notifyTaskManager) {
        this.notifyTaskManager = notifyTaskManager;
    }

}
